package org.apache.maven.plugin.googlecode;

import org.xml.sax.helpers.DefaultHandler;
import org.apache.maven.plugin.changes.Release;
import org.apache.maven.plugin.changes.Action;
import org.w3c.tidy.Tidy;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.CharacterData;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

/**
 * 
 */
public class GoogleCodeAnnouncementParser extends DefaultHandler
{

    private List issues = new ArrayList();

    public GoogleCodeAnnouncementParser( String xmlPath )
    {
        File xml = new File( xmlPath );

        parseGoogleCode( xml );
    }

    public GoogleCodeAnnouncementParser( File xmlPath )
    {
        parseGoogleCode( xmlPath );
    }

    public void parseGoogleCode( File xml )
    {
      Tidy tidy=new Tidy();
      tidy.setQuiet(true);
      tidy.setShowWarnings(false);
      
      try {
        Document doc=tidy.parseDOM(new FileInputStream(xml), null);
        NodeList nl = doc.getElementsByTagName("td");
        GoogleCodeAnnouncement issue = null;

        System.err.println("Parsing");
        for(int i=0; i<nl.getLength(); i++) {
          Element elt = (Element)nl.item(i);
          String clz = elt.getAttribute("class");
          System.err.println("Class is "+clz);
          if(clz.startsWith("vt id")) {
            issue = new GoogleCodeAnnouncement();
            issues.add(issue);
            issue.setKey(getIssueKey(elt)); 
            issue.setLink("");
            issue.setAssignee("cromwellian@gmail.com");
          }
          else if(clz.startsWith("vt col_1")) {
            String type = stringify(elt);
            issue.setType(type);
            System.err.println("Set type "+type);
          }
          else if(clz.startsWith("vt col_2")) {
            issue.setStatus(stringify(elt));
            issue.setResolution(issue.getStatus());
          } else if(clz.startsWith("vt col_3")) {
            String milestone = stringify(elt);
            if(milestone != null) milestone=milestone.replaceFirst("^Release", "");
            if(milestone != null && milestone.startsWith(".")) milestone="0"+milestone;
            System.err.println("fixversion "+milestone);
            
            issue.setFixVersion(milestone);          
          }
          else if(clz.startsWith("vt col_4")) {
            String summary = stringify(elt);
            System.err.println("Set summary "+summary);
            
            issue.setSummary(summary);
          }
        }
        
      } catch (FileNotFoundException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
    }

  private String getIssueKey(Element elt) {
    return stringify(elt);
  }

  private String stringify(Node elt) {
    String res="";
    if(elt.getNodeType() == Node.TEXT_NODE || elt.getNodeType() == Node.CDATA_SECTION_NODE) {
      res += ((CharacterData)elt).getData();
      return res.trim();
    }
    for(Node n = elt.getFirstChild(); n!= null; n = n.getNextSibling()) {
      res+=stringify(n);
    }
    return res;
  }

  public List getIssues()
    {
        return this.issues;
    }

    public List getReleases( List issues )
    {
        // A Map of releases keyed by fixVersion
        Map releasesMap = new HashMap();

        // Loop through all issues looking for fixVersions
        for ( int i = 0; i < issues.size(); i++ )
        {
            GoogleCodeAnnouncement issue = (GoogleCodeAnnouncement) issues.get( i );
            // Do NOT create a release for issues that lack a fixVersion
            if ( issue.getFixVersion() != null )
            {
                // Try to get a matching Release from the map
                Release release = (Release) releasesMap.get( issue.getFixVersion() );
                if ( release == null )
                {
                    // Add a new Release to the Map if it wasn't there
                    release = new Release();
                    release.setVersion( issue.getFixVersion() );
                    releasesMap.put( issue.getFixVersion(), release );
                }

                // Add this issue as an Action to this release
                Action action = createAction( issue );
                release.addAction( action );
            }
        }

        // Extract the releases from the Map to a List
        List releasesList = new ArrayList();
        for ( Iterator iterator = releasesMap.entrySet().iterator(); iterator.hasNext(); )
        {
            Release o = (Release) ( (Map.Entry) iterator.next() ).getValue();
            releasesList.add( o );
        }
        return releasesList;
    }

    /**
     * Create an <code>Action</code> from a  GoogleCode issue.
     *
     * @param issue The issue to extract the information from
     * @return An <code>Action</code>
     */
    private Action createAction( GoogleCodeAnnouncement issue )
    {
        Action action = new Action();

        action.setIssue(issue.getKey() );

        String type = "";
        if ( issue.getType().equals( "Defect" ) )
        {
            type = "fix";
        }
        else if ( issue.getType().equals( "Enhancement" ) )
        {
            type = "add";
        }
        else
        {
            type = "update";
        }
        action.setType( type );

        action.setDev( issue.getAssignee() );

        // Set dueTo to the empty String instead of null to make Velocity happy
        action.setDueTo( "" );
        //action.setDueTo( issue.getReporter() );

        action.setAction( issue.getSummary() );
        return action;
    }
}